package sqlexplorer.ui.views;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.part.ViewPart;

import sqlexplorer.application.ConnectionsController;
import sqlexplorer.application.MetaDataController;
import sqlexplorer.application.exceptions.NotConnectedException;
import sqlexplorer.domain.metadata.ColumnMetaData;
import sqlexplorer.domain.metadata.TableMetaData;
import sqlexplorer.ui.model.ColumnNode;
import sqlexplorer.ui.model.DatabaseNode;
import sqlexplorer.ui.model.IComposite;
import sqlexplorer.ui.model.TableNode;

public class MetaDataView extends ViewPart implements Observer{
	
	public static final String ID="sqlexplorer.ui.views.metadataview";
	
	private TreeViewer m_treeViewer;
	
	private TableMetaData[] m_tableMetaData;
	
	@Override
	public void createPartControl(Composite parent){
		parent.setLayout(new GridLayout(1,true));
		parent.setBackground(new Color(parent.getDisplay(),255,255,255));
		
		m_treeViewer=new TreeViewer(parent,SWT.SINGLE);
		m_treeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
		m_treeViewer.setLabelProvider(new TreeLabelProvider());
		m_treeViewer.setContentProvider(new TreeContentProvider());
		
		m_tableMetaData=null;
		MetaDataController.getInstance().addObserver(this);
		m_treeViewer.setInput(new Object[]{new DatabaseNode("Please connect to a database.")});
		
		//test input tree
		/*TableNode tn=new TableNode("table");
		DatabaseNode dn=new DatabaseNode("database",new Object[]{tn});
		tn.setParent(dn);
		m_treeViewer.setInput(new Object[]{dn});*/
	}
	
	@Override
	public void setFocus(){
		m_treeViewer.getControl().setFocus();
	}
	
	@Override
	public void update(Observable observable, Object argument){
		if(observable instanceof MetaDataController){
			if(argument.equals("connectionChanged")){
				try{
					m_tableMetaData=MetaDataController.getInstance().getMetaData();
					
					//map to the ui tree model
					DatabaseNode dn=new DatabaseNode(ConnectionsController.getInstance().getActiveDatabaseConnection().getConnectionName()+" : "+
							ConnectionsController.getInstance().getActiveDatabaseConnection().getDatabaseType().toString());
					ArrayList<TableNode> tableNodes=new ArrayList<TableNode>();
					
					for(TableMetaData tmd:m_tableMetaData){
						TableNode tn=new TableNode(tmd.getTableName()+" : "+tmd.getTableType());
						ArrayList<ColumnNode> columnNodes=new ArrayList<ColumnNode>();
						
						for(ColumnMetaData cmd:tmd.getColumns()){
							columnNodes.add(new ColumnNode(cmd.getColumnName()+" : "+cmd.getDataType(),tn));
						}
						
						tn.setChildren(columnNodes.toArray(new Object[0]));
						tn.setParent(dn);
						
						tableNodes.add(tn);
					}
					
					dn.setChildren(tableNodes.toArray(new Object[0]));
					
					//refresh the tree
					m_treeViewer.setInput(new Object[]{dn});
				}catch(NotConnectedException exc){
					MessageBox msgBox=new MessageBox(getSite().getShell(),SWT.ICON_WARNING|SWT.OK);
					msgBox.setText("Warning");
					msgBox.setMessage("Please connect to a database.");
					
					msgBox.open();
				}catch(SQLException exc){
					MessageBox msgBox=new MessageBox(getSite().getShell(),SWT.ICON_ERROR|SWT.OK);
					msgBox.setText("Error");
					msgBox.setMessage("Cannot get meta data for the database.");
					
					msgBox.open();
				}
			}else if(argument.equals("connectionCancelled")){
				m_treeViewer.setInput(new Object[]{new DatabaseNode("Please connect to a database.")});
			}
		}
	}
	
	//iterates throw the model
	private class TreeContentProvider extends ArrayContentProvider implements ITreeContentProvider{
		
		@Override
		public Object[] getChildren(Object parentElement){
			if(parentElement instanceof IComposite){
				return ((IComposite)parentElement).getChildren();
			}else{
				return null;
			}
		}
		
		@Override
		public Object getParent(Object element){
			if(element instanceof IComposite){
				return ((IComposite)element).getParent();
			}else{
				return null;
			}
		}
		
		@Override
		public boolean hasChildren(Object element){
			if(element instanceof IComposite){
				return ((IComposite)element).hasChildren();
			}else{
				return false;
			}
		}
	}
	
	//set the Data in the Treeview
	private class TreeLabelProvider extends LabelProvider{
		
		@Override
		public Image getImage(Object element){
			return null;
		}
		
		@Override
		public String getText(Object element){
			if(element!=null){
				if(element instanceof DatabaseNode){
					return ((DatabaseNode)element).getName();
				}else if(element instanceof TableNode){
					return ((TableNode)element).getName();
				}else if(element instanceof ColumnNode){
					return ((ColumnNode)element).getName();
				}else{
					return "Undefined node";
				}
			}else{
				return "Element is null";
			}
		}
	}
}
